package com.xbongbong.pro.statistic.service.result;

import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaySheetTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.service.toolbox.statistic.util.ChartResultUtil;
import com.xbongbong.pro.statistic.constant.ChartI18Constant;
import com.xbongbong.pro.statistic.enums.IndicatorRuleEnum;
import com.xbongbong.pro.statistic.enums.NumFormatEnum;
import com.xbongbong.pro.statistic.enums.SystemCodeEnum;
import com.xbongbong.pro.statistic.enums.ValueTypeEnum;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.pro.statistic.result.pojo.MomYoyTimeListPojo;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultDTO;
import com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultInfoDTO;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartResultDetailVO;
import com.xbongbong.pro.statistic.through.pojo.dto.ThroughDTO;
import com.xbongbong.saas.enums.FundAccountFlowEnum;
import com.xbongbong.saas.enums.business.PayPlanEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 付款计划相关统计
 *
 * @author 徐俊杰
 * @version v1.0
 * @date 2019/3/13 14:13
 * @since v1.0
 */
@Service
public class JxcPayResult extends ChartResultParentService implements ChartResultSystem {

    @Override
    public Object getTarget(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            case PAY_ED_CHART:
                return payEdChart(chartResultPojo, chartResultDetailVO);
            case PAY_BAD_CHART:
                return payBadChart(chartResultPojo, chartResultDetailVO);
            case PAY_RED_CHART:
                return payRedChart(chartResultPojo, chartResultDetailVO);
            default:
                break;
        }
        return null;
    }

    @Override
    public Object getValueTarget(ChartResultPojo chartResultPojo) throws XbbException {
        SystemCodeEnum systemCodeEnum = chartResultPojo.getSystemCodeEnum();
        switch (systemCodeEnum) {
            case PAY_ED_HOME:
                return payEdBoard(chartResultPojo);
            case WRITE_OFF_PAY_HOME:
                return payWriteOffBoard(chartResultPojo);
            //应付款（简报看板）
            case PAY_UN_BOARD:
                return payUnBoard(chartResultPojo);
            //应付款（资金管理）
            case PAY_UN_HOME:
                return payUnHome(chartResultPojo);
            //付款坏账（资金管理）
            case PAY_BAD_HOME:
                return payBadHome(chartResultPojo);
            //红冲付款（资金管理）
            case PAY_RED_HOME:
                return payRedHome(chartResultPojo);
            default:
                break;
        }
        return null;
    }

    /**
     * 付款单（资金账户统计用）
     *
     * @param chartResultPojo 获取图表结果参数pojo
     * @return java.lang.String
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/18 15:45
     * @since v1.0
     *
     * @since v2.0 v2.0 2021/5/31 原先指标叫做付款，现在指标叫做流出，计算规则变成流出 = 原逻辑 + 其他收入单的收入汇总 + 支出类型的调拨单
     */
    double paySheet4FundAccount(ChartResultPojo chartResultPojo) throws XbbException {
        /*BoolQueryBuilder boolQueryBuilder = chartQueryHelp.paySheetQuery4Account(chartResultPojo);
        //付款金额为求和字段
        String sumField = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.AMOUNT);
        //付款时间为时间字段
        String fieldTime = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.REAL_PAY_TIME);
        ElasticAggsPojo double4Agg = systemChartHelp.getDouble4Agg(chartResultPojo, ValueTypeEnum.VALUE_TYPE, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, boolQueryBuilder, fieldTime, sumField);
        return double4Agg.getTotal();*/
        //封装查询流出的查询条件
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.FundAccountOutQuery4Account(chartResultPojo);
        //单据金额为求和字段
        String sumField = FundAccountFlowEnum.SHEET_AMOUNT.getAttr();
        //付款时间为时间字段
        String fieldTime = FundAccountFlowEnum.SHEET_TIME.getAttr();
        ElasticAggsPojo double4Agg = systemChartHelp.getDouble4Agg(chartResultPojo, ValueTypeEnum.VALUE_TYPE, IndexTypeEnum.IDX_FUND_ACCOUNT_FLOW, boolQueryBuilder, fieldTime, sumField);
        double total = Double.parseDouble(double4Agg.getTotal());
        if(total == 0.00){
            return total;
        }
        return -total;
    }

    /**
     * 付款坏账（首页）
     *
     * @param chartResultPojo 获取图表结果参数pojo
     * @return java.lang.Object
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/10 17:31
     * @since v1.0
     */
    private Object payBadHome(ChartResultPojo chartResultPojo) throws XbbException {
        //ES获取坏账付款金额
        List<String> badCodeList = PaySheetTypeEnum.getBadCodeList();
        ElasticAggsPojo elasticAggsPojo = payEd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, badCodeList);
        return ChartResultUtil.formatValue2String(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), elasticAggsPojo.getTotal(), NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 红冲付款（首页）
     *
     * @param chartResultPojo 获取图表结果参数pojo
     * @return java.lang.Object
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/10 17:32
     * @since v1.0
     */
    private Object payRedHome(ChartResultPojo chartResultPojo) throws XbbException {
        //ES获取红冲付款金额
        List<String> redCodeList = PaySheetTypeEnum.getRedCodeList();
        ElasticAggsPojo elasticAggsPojo = payEd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, redCodeList);
        return ChartResultUtil.formatValue2String(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), elasticAggsPojo.getTotal(), NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 已付款
     * @param chartResultPojo
     * @return java.lang.String 
     * @author zcp
     * @date 2019/4/15 21:42
     * @since v1.0
     * @version v1.0
     */
    public String payEdBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //已付款
        List<String> notBadCodeList = PaySheetTypeEnum.getNotBadCodeList();
        ElasticAggsPojo elasticAggsPojo = payEd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE, notBadCodeList);
        return ChartResultUtil.formatValue2String(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), elasticAggsPojo.getTotal(), NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 付款核销
     * @param chartResultPojo
     * @return java.lang.String
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public String payWriteOffBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //付款核销只统计4种：已核销、预付款核销、红冲已核销、红冲预付款核销
        List<String> writeOffCodeList = PaySheetTypeEnum.getWriteOffCodeList();
        ElasticAggsPojo elasticAggsPojo = payEd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.VALUE_TYPE, writeOffCodeList);
        return ChartResultUtil.formatValue2String(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), elasticAggsPojo.getTotal(), NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }
    /**
     * 应付款（简报看板）
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @return java.lang.String
     * @author 徐俊杰
     * @date 2019/3/13 15:24
     * @since v1.0
     */
    public String payUnBoard(ChartResultPojo chartResultPojo) throws XbbException {
        //ES获取应付款金额
        double unAmount = payUn(chartResultPojo);
        return ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, chartResultPojo.isThousandSwitch(), unAmount, NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 应付款（首页）
     *
     * @param chartResultPojo     内部存系统指标统计时需要的参数
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/15 16:10
     * @since v1.0
     */
    public Object payUnHome(ChartResultPojo chartResultPojo) throws XbbException {
        double unAmount = payUn(chartResultPojo);
        return ChartResultUtil.formatValue2Double(false, ValueTypeEnum.VALUE_MONEY, false, unAmount, NumFormatEnum.getByCode(chartResultPojo.getNumFormat()), chartResultPojo.getNumFormatFlag());
    }

    /**
     * 已付款（首页）
     *
     * @param chartResultPojo     内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException
     * @author 徐俊杰
     * @date 2019/3/18 16:15
     * @since v1.0
     */
    public Object payEdHome(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> notBadCodeList = PaySheetTypeEnum.getNotBadCodeList();
        ElasticAggsPojo elasticAggsPojo = payEd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, notBadCodeList);
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        //是否画入表格内 0否1是
        Integer tableFlag = 1;
        String legend = SystemCodeEnum.PAY_ED_HOME.getName();
        String unit = "元";
        Boolean totalFlag = true;
        String valueTitle = SystemCodeEnum.PAY_ED_HOME.getName();
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, tableFlag, legend, unit, totalFlag, valueTitle);
    }

    /**
     * 得到应付款总金额（应付款只统计总数，无列表等趋势图统计）
     * @param chartResultPojo
     * @return double
     * @author zcp
     * @date 2019/5/10 15:16
     * @since v1.0
     * @version v1.0
     */
    public double payUn(ChartResultPojo chartResultPojo) throws XbbException {
        String sumField = PayPlanEnum.getEsAttr4Keyword(PayPlanEnum.UN_AMOUNT);
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.payQuery4Un(chartResultPojo);
        return systemChartHelp.getDouble4Total(IndexTypeEnum.IDX_SAAS_PAY_PLAN, boolQueryBuilder, sumField);
    }

    /**
     * 图表中心，付款金额分析
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/14 10:25
     * @since v1.0
     */
    private Object payEdChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.PAY_ED_CHART_TITLE).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1, unit1);
        //已付款：非坏账，不限制红冲
        List<String> notBadCodeList = PaySheetTypeEnum.getNotBadCodeList();
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(chartResultPojo, legendList, unitList, notBadCodeList);

        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.TOTAL_PAY_AMOUNT));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 图表中心，付款坏账金额分析
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/14 10:31
     * @since v1.0
     */
    private Object payBadChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        //查询条件封装坏账的，isBad=1
        List<String> badCodeList = PaySheetTypeEnum.getBadCodeList();
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.paySheetQuery(chartResultPojo, badCodeList);
        String fieldTime = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.REAL_PAY_TIME);
        String sumField = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.AMOUNT);
        /*
         得到坏账金额
        */
        ElasticAggsPojo elasticAggsPojo = systemChartHelp.getDouble4Agg(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, boolQueryBuilder, fieldTime, sumField);
        //设置值的类型
        chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        //处理穿透
        ThroughDTO throughDTO = new ThroughDTO(chartResultPojo, chartResultPojo.getSystemCodeEnum());
        return systemChartHelp.packageResult4One(elasticAggsPojo, chartResultPojo, chartResultDetailVO, throughDTO, 1, I18nMessageUtil.getMessage(I18nStringConstant.AMOUNT_OF_BAD_DEBTS_COMMON), chartResultPojo.getUnit(), true, I18nMessageUtil.getMessage(ChartI18Constant.TOTAL_PAYMENT_BAD_AMOUNT));
    }

    /**
     * 图表中心，付款红冲金额分析
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param chartResultDetailVO 结果
     * @return java.lang.Object
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/14 10:33
     * @since v1.0
     */
    private Object payRedChart(ChartResultPojo chartResultPojo, ChartResultDetailVO chartResultDetailVO) throws XbbException {
        List<String> legendList = Arrays.asList(I18nMessageUtil.getMessage(ChartI18Constant.PAY_RED_CHART_TITLE).split(","));
        String unit = systemChartHelp.getUnit(I18nMessageUtil.getMessage(CommonConstant.YUAN));
        String unit1 = systemChartHelp.getUnit("%");
        List<String> unitList = Arrays.asList(unit, unit, unit, unit1, unit1);
        //红冲：非坏账，红冲
        List<String> redCodeList = PaySheetTypeEnum.getRedCodeList();
        StatisticResultDTO statisticResultDto = getStatisticResultDto4MomYoy(chartResultPojo, legendList, unitList, redCodeList);

        //右侧展示总数
        statisticResultDto.setTotalFlag(true);
        statisticResultDto.setValueTitle(I18nMessageUtil.getMessage(ChartI18Constant.TOTAL_AMOUNT_RED_PAYMENT_AMOUNT));
        chartResultDetailVO = systemChartHelp.packageResult(statisticResultDto, chartResultPojo, chartResultDetailVO);
        return chartResultDetailVO;
    }

    /**
     * 获取并封装环比、同比统计结果
     * @param chartResultPojo 参数pojo
     * @param legendList 图的legend
     * @param unitList 各条线的单位，与legendList大小一致
     * @param typeList 类型
     * @return com.xbongbong.pro.statistic.result.pojo.dto.StatisticResultDTO
     * @throws XbbException 异常
     * @author 徐俊杰
     * @date 2020/3/14 10:23
     * @since v1.0
     */
    private StatisticResultDTO getStatisticResultDto4MomYoy(ChartResultPojo chartResultPojo, List<String> legendList, List<String> unitList, List<String> typeList) throws XbbException {
        chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        //先把chartResultPojo拷贝出一份，下面都用chartResultPojoCopy，防止时间的变更对原有chartResultPojo内参数的影响
        Integer startTime = chartResultPojo.getStartTime();
        Integer endTime = chartResultPojo.getEndTime();
        //环比，上月开始--截止，startTime的前一个月，作为环比的开始时间；endTime的前一个月，作为环比的截止时间
        Integer lastMonthStartTime = DateUtil.getFirstDateOfLastMonth(startTime);
        Integer lastMonthEndTime = DateUtil.getFirstDateOfLastMonth(endTime);
        //同比，上年同期（上年同一个月）开始--截止：startTime的上年同月，作为同比的开始时间；endTime的上年同月第一天，作为同比的截止时间
        Integer lastYearStartTime = DateUtil.getFirstDateOfLastYear(startTime);
        Integer lastYearEndTime = DateUtil.getFirstDateOfLastYear(endTime);

        //------当前筛选时间的结果
        ElasticAggsPojo thisMonthAggsPojo = payEd2ElasticAggsPojo(chartResultPojo, ValueTypeEnum.ARRAY_TYPE, typeList);
        ChartResultPojo chartResultPojoCopy = new ChartResultPojo();
        BeanUtil.copyProperties(chartResultPojo, chartResultPojoCopy);
        //------环比结果，把开始结束时间置为环比的开始结束
        chartResultPojoCopy.setStartTime(lastMonthStartTime);
        chartResultPojoCopy.setEndTime(lastMonthEndTime);
        //获取环比同比各自的时间列表
        List<Integer> startTimeList = chartResultPojoCopy.getStartTimeList();
        MomYoyTimeListPojo momYoyTimeListPojo = ChartResultUtil.momYoyTimeListPojo(startTimeList);
        //环比时间处理
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, true, startTime, endTime);
        chartResultPojoCopy.setStartTimeList(momYoyTimeListPojo.getMomTimeListPojo().getStartTimeList());
        chartResultPojoCopy.setEndTimeList(momYoyTimeListPojo.getMomTimeListPojo().getEndTimeList());
        //------环比结果
        ElasticAggsPojo lastMonthAggsPojo = payEd2ElasticAggsPojo(chartResultPojoCopy, ValueTypeEnum.ARRAY_TYPE, typeList);
        //------同比结果，把开始结束时间置为同比的开始结束
        chartResultPojoCopy.setStartTime(lastYearStartTime);
        chartResultPojoCopy.setEndTime(lastYearEndTime);
        //同比时间处理
        ChartResultUtil.momOrYoyTime(chartResultPojoCopy, false, startTime, endTime);
        chartResultPojoCopy.setStartTimeList(momYoyTimeListPojo.getYoyTimeListPojo().getStartTimeList());
        chartResultPojoCopy.setEndTimeList(momYoyTimeListPojo.getYoyTimeListPojo().getEndTimeList());
        //------同比结果
        ElasticAggsPojo lastYearAggsPojo = payEd2ElasticAggsPojo(chartResultPojoCopy, ValueTypeEnum.ARRAY_TYPE, typeList);
        //------处理环比、同比比例
        ElasticAggsPojo resultMom = systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastMonthAggsPojo);
        ElasticAggsPojo resultYoy = systemChartHelp.getMomYoyResult(thisMonthAggsPojo, lastYearAggsPojo);

        List<StatisticResultInfoDTO> statisticResultInfoDtoList = systemChartHelp.getInfoDtos4MomYoy(chartResultPojo, legendList, unitList, thisMonthAggsPojo, lastMonthAggsPojo, lastYearAggsPojo, resultMom, resultYoy);
        return new StatisticResultDTO(true, thisMonthAggsPojo.getTotal(), null, statisticResultInfoDtoList);
    }

    /**
     * 获取已付款金额的ElasticAggsPojo
     *
     * @param chartResultPojo 内部存系统指标统计时需要的参数
     * @param valueTypeEnum   值的类型
     * @param typeList 付款单类型限制
     * @return com.xbongbong.paas.elasticsearch.pojo.ElasticAggsPojo
     * @author 徐俊杰
     * @date 2019/3/18 16:10
     * @since v1.0
     */
    private ElasticAggsPojo payEd2ElasticAggsPojo(ChartResultPojo chartResultPojo, ValueTypeEnum valueTypeEnum, List<String> typeList) throws XbbException {
        BoolQueryBuilder boolQueryBuilder = chartQueryHelp.paySheetQuery(chartResultPojo, typeList);
        //根据权限决定请求付款金额还是核销金额
        String sumField;
        Boolean performancePk = chartResultPojo.getPerformancePk();
        IndicatorRuleEnum indicatorRuleEnum = chartResultPojo.getSystemCodeEnum().getIndicatorRuleEnum();
        boolean writeOffFlag = chartDtoHelp.judgePermissionAndIfCheck(chartResultPojo) || performancePk || Objects.equals(indicatorRuleEnum, IndicatorRuleEnum.WRITE_OFF_PAY);
        if (writeOffFlag) {
            sumField = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.WRITE_OFF_AMOUNT);
        } else {
            sumField = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.AMOUNT);
        }
        String fieldTime = PaySheetEnum.getEsAttr4Keyword(PaySheetEnum.REAL_PAY_TIME);
        chartResultPojo.setValueTypeEnum(ValueTypeEnum.VALUE_MONEY);
        return systemChartHelp.getDouble4Agg(chartResultPojo, valueTypeEnum, IndexTypeEnum.IDX_SAAS_PAYPLAN_SHEET, boolQueryBuilder, fieldTime, sumField);
    }

}
